from common.es_core.es_interface import es_search_interface
import logging

_LOGGER = logging.getLogger(__name__)


class UserFilter(object):
    """
    用戶數據分析藉由某種條件將用戶進行過濾找到關注的用戶，此模塊
    依照各業務系統實踐如何進行用戶的過濾，再將用戶多表的數據進行
    聚合數據匯總。
    """
    def __init__(self, user_pool=None, merchant_name='loki'):
        self.merchant_name = merchant_name
        self.user_pool = user_pool

    def get_user_pool(self):
        return self.user_pool

    def get_user_count(self):
        return len(self.user_pool)

    @staticmethod
    def _get_script_aggregate_dsl(target_fields):
        field_key = 'field'
        if isinstance(target_fields, list):
            source_field = ''
            for f in target_fields:
                if not source_field:
                    source_field = "doc.{}.value".format(f)
                else:
                    operator = '+' if f[0] != '-' else '-'
                    f = f if f[0] != '-' else f[1:]
                    source_field += operator + "doc.{}.value".format(f)
            target_fields = {'source': source_field}
            field_key = 'script'
        return field_key, target_fields

    @staticmethod
    def _get_stage_filter_script(stage_floor, stage_ceiling):
        script_list = []
        if stage_floor is not None and isinstance(stage_floor, (int, float,)):
            stage_floor = 'params.amount > {}'.format(stage_floor)
            script_list.append(stage_floor)
        if stage_ceiling is not None and isinstance(stage_ceiling, (int, float,)):
            stage_ceiling = 'params.amount <= {}'.format(stage_ceiling)
            script_list.append(stage_ceiling)
        assert len(script_list) > 0
        script = '&&'.join(script_list)
        return script

    def stage_filter(self, event_id, target_fields, operation, start_time,
                     end_time, stage_floor=None, stage_ceiling=None, max_size=50000, custom_filter=None,
                     custom_not_filter=None):
        assert operation in ('sum', 'value_count', 'script',)
        field_key, target_fields = self._get_script_aggregate_dsl(target_fields)
        script = self._get_stage_filter_script(stage_floor, stage_ceiling)
        _filter = [
            {'range': {
                "_event_time": {
                    "gte": start_time.timestamp(),
                    "lt": end_time.timestamp()
                }
            }},
        ]
        if custom_filter:
            assert isinstance(custom_filter, list)
            _filter += custom_filter
        if event_id:
            if not isinstance(event_id, list):
                event_id = [event_id]
            _filter += [{"terms": {"_event_id": event_id}}]
        if self.user_pool is not None:
            _filter += [{'terms': {'_user_id': self.user_pool}}]
        aggregate_dsl = {
            "query": {"bool": {"filter": _filter}},
            "size": 0,
            "aggs": {
                "distinct_user_id": {
                    "terms": {"field": "_user_id", "size": max_size},
                    "aggs": {
                        "amount": {"sum" if operation == 'sum' else 'value_count': {field_key: target_fields}},
                        "amount_filter": {"bucket_selector": {"buckets_path": {"amount": "amount"},
                                                              "script": script}}
                    }
                }
            }
        }
        if custom_not_filter:
            aggregate_dsl['query']['bool']['must_not'] = custom_not_filter
        resp_json = es_search_interface(self.merchant_name, aggregate_dsl)
        buckets = resp_json['aggregations']['distinct_user_id']['buckets']
        user_id_list = []
        for bucket in buckets:
            user_id_list.append(bucket['key'])
        self.user_pool = user_id_list

    def event_user_filter(self, event_id, start_time, end_time, custom_filter=None, custom_not_filter=None, size=40000):
        if not isinstance(event_id, list):
            event_id = [event_id]
        _filter = [
            {"terms": {"_event_id": event_id}},
            {'range': {"_event_time": {"gte": start_time.timestamp(), "lt": end_time.timestamp()}}}
        ]
        if custom_filter:
            assert isinstance(custom_filter, list)
            _filter += custom_filter
        if self.user_pool is not None:
            _filter.append({'terms': {'_user_id': self.user_pool}})
        aggs_dsl = {
            "query": {"bool": {"filter": _filter}},
            "size": 0,
            "aggs": {
                "distinct_user_id": {
                    "terms": {
                        "field": "_user_id",
                        "size": size
                    },
                    "aggs": {}
                }
            }
        }
        if custom_not_filter:
            aggs_dsl['query']['bool']['must_not'] = custom_not_filter
        resp_json = es_search_interface(self.merchant_name, aggs_dsl)
        buckets = resp_json['aggregations']['distinct_user_id']['buckets']
        user_id_list = []
        for bucket in buckets:
            user_id_list.append(bucket['key'])
        self.user_pool = user_id_list
